﻿using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Models.Wishire.entity;
using Models.Wishire.Operator;

namespace Models.Wishire
{

    /*旅行问题化简为
        地图上有n个点，你需要按照景点（必逛）--美食---
        生成方案流程
         先定义一个Travel类
        添加target（set)
        添加出发地点（set）
        添加默认地点（add）
        Travel.init()//初始化
        Travel.generate();//生成路线
     */
    public class Travel
    {

        /*
         * 
         * 需要传入的参数有：plan的开始日期
         * 需要传入的参数有：plan的结束日期
         * planId;
         * 开始地点Hotel
         * HotelName
         * 
         * */
        public int times = 0;
        public int day1 = 0;
        public int day2 = 0;
        private List<target_st> target = new List<target_st>();
        private List<place> place;
        private target_st Start_place;
        const int N = 205;
        public double[,] dist = new double[N,N];
        public double[] dis = new double[N];
        private bool[] vis = new bool[N];
        private int[] pri = new int[N];
        private int[] maxn_array = new int[N];
        private int[] temp_ans = new int[N];
        private List<target_st> temp_list = new List<target_st>();
        public int planId;
        int maxn = 0;
        const double R = 6378.137;
        public void Set_target(List<target_st> temp)
        {
            for(int i=0; i<temp.Count; i++)
            {
                target_st now = temp[i];
                //target_st test = new target_st();
                now.SetValue(10000);
                now.SetTag(1);
                target.Add(now);
            }
        }
        public void Set_startPlace (target_st temp)
        {
            Start_place = temp;
        }
        public void Add_target(target_st temp)
        {
            target_st now = temp;
            now.SetValue(10000);
            target.Add(now);
        }
        public void Add_target(List<target_st> temp)
        {
            for (int i = 0; i < temp.Count; i++)
            {
                target_st now = temp[i];
                //now.SetValue(10000);
                target.Add(now);
            }
        }
        private static double rad(double d)
        {
            return d * Math.PI / 180.0;
        }
        //计算距离
        double cal_dist(target_st i, target_st j)
        {
            double xLat = i.GetTargetLat();
            double yLat = j.GetTargetLat();
            double xLng = i.GetTargetLng();
            double yLng = j.GetTargetLng();
            double radLat1 = rad(xLat);
            double radLat2 = rad(yLat);
            double a = radLat1 - radLat2;
            double b = rad(xLng) - rad(yLng);
            double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2)));
            s = s * R;
            s = Math.Round(s * 10000) / 10000;
            return s;
        }
        //初始化
        double abs(double x)
        {
            return x > -x ? x : -x;
        }
        bool judge_same(int i,int j)
        {

            if(i == 1 && j == 10)
            {
                int w = 1;
            }
            double t = target[i].GetTargetLat() - target[j].GetTargetLat();
            double k = target[i].GetTargetLng() - target[j].GetTargetLng();
            return cal_dist(target[i], target[j]) <= 0.1;
        }
        int max(int a,int b)
        {
            return a > b ? a : b;
        }
        public void init()
        {
            int len = target.Count;
            for(int i = 0; i < len; i++)
            {
                int flag = 0;
                if(i == 2)
                {
                    int w = 1;
                }
                for (int j = 0; j < len; j++)
                {
                    if (judge_same(i, j) &&i!=j) 
                           flag = 1;
                    
                }
                if(flag == 0 || (flag == 1 && target[i].GetTag() == 1)) 
                    temp_list.Add(target[i]);
            }
            target = temp_list;
            len = target.Count;
            for(int i = 0; i < len; i++)
                for(int j = 0; j < len;j++)
                {
                    dist[i,j] = cal_dist(target[i], target[j]);
                }
            for(int i=0; i < len; i++)
            {
                dis[i] = cal_dist(target[i], Start_place);
                double t = 10000 / (dis[i] + 1) + target[i].GetValue();
                target[i].SetValue((int)t);
            }
        }
        int cnt = 0;
        int cal_value(target_st i, target_st j)
        {
            double dis = cal_dist(i, j);
            double value = 0;
            if (j.GetTag() == 1) value += 10000;
            value += 10000 / (dis + 1);
            return (int)value;
        }
        int  dfs(int pos,int n)
        {
            int flag = 0;
            if(pos == n+1)
            {
                int sumvalue = 0;
                sumvalue += cal_value(Start_place, target[pri[1]]);
                sumvalue += cal_value(Start_place, target[pri[n]]);
                for (int i = 1; i <= n-1; i++)
                    sumvalue += cal_value(target[pri[i]], target[pri[i+1]]);
                if (sumvalue > maxn)
                {
                    maxn = sumvalue;
                    for (int i = 1; i <= n; i++) temp_ans[i] = pri[i];
                    temp_ans[1] = pri[1];
                    temp_ans[2] = pri[2];
                    temp_ans[3] = pri[3];
                    /*Console.WriteLine($"第{++cnt}个方案：");
                    Console.WriteLine(target[pri[1]].GetTargetName());
                    Console.WriteLine(target[pri[2]].GetTargetName());
                    Console.WriteLine(target[pri[3]].GetTargetName());
                    Console.WriteLine();*/
                }
                return 1;
            }
            int len = target.Count;
            for(int i=0; i < len; i++)
            {
                if (!vis[i])
                {
                    if (pos <= 2 && target[i].GetMustNight() == 1) continue;
                    pri[pos] = i;
                    vis[i] = true;
                    flag = max(dfs(pos + 1,n),flag);
                    vis[i] = false;
                }
            }
            return flag;
        }

        //插入数据库中
        void insert_ans(target_st target,int index,int planId)
        {
            answer ans = new answer();
            ans.SetLat(target.GetTargetLat());
            ans.SetLng(target.GetTargetLng());
            ans.SetName(target.GetTargetName());
            ans.SetIndex(index);
            ans.SetPlanId(planId);
            ans.SetIfDeleted(0);
            opdataanswer op = new opdataanswer();
            Console.WriteLine("Insert");
            op.answerInsert(ans);
        }

        public List<answer> generate() 
        {
            List<answer> ans = new List <answer>();
            int flag = dfs(1, day1);
            int index = 0;
            for(int j=1;j<=day1 && flag == 1;j++)
                insert_ans(target[temp_ans[j]], ++index,planId);
            for (int j = 1; j <= day1; j++)
                vis[temp_ans[j]] = true;
            Console.WriteLine(maxn);
            flag = 0;
            maxn = 0;
            int max_target = day1 + times * 3 + day2;
            if (max_target > target.Count)
            {
                //由于旅行天数太多超过推荐  因此方案生成可能出现问题
                times = (target.Count - day1)/3;
                day2 = target.Count - times * 3 - day1;
            }
            for (int i = 1; i <= times; i++)
            {
                //Console.WriteLine($"Start：");
                flag = dfs(1,3);
                //Console.WriteLine($"Day{i}：");
                //Console.WriteLine(target[temp_ans[1]].GetTargetName());
                //Console.WriteLine(target[temp_ans[2]].GetTargetName());
                //Console.WriteLine(target[temp_ans[3]].GetTargetName());
                for(int j=1;j<=3 && flag == 1;j++)
                    insert_ans(target[temp_ans[j]], ++index, planId);
                for (int j = 1; j <= 3; j++)
                    vis[temp_ans[j]] = true;
                // opdataanswer opdataanswer = new opdataanswer();
                //opdataanswer.swapanswer(1, 2, 3);
                //opdataanswer.answerDelete(1, 1);
                Console.WriteLine(maxn);
                maxn = 0;
            }
            if (times >= 0)
            {
                flag = dfs(1, day2);
                for (int j = 1; j <= day2 && flag == 1; j++)
                    insert_ans(target[temp_ans[j]], ++index, planId);
                for (int j = 1; j <= day2; j++)
                    vis[temp_ans[j]] = true;
                Console.WriteLine(maxn);
                maxn = 0;
            }
            opdataanswer opans = new opdataanswer();
            ans = opans.answerFind_planId(planId);
            return ans;
            //new List<target_st>();
        }
}
}
